import { Module, Mutation } from "vuex";
import store, { GlobalDataProps,actionWrapper } from ".";
import { v4 as uuidv4 } from "uuid";
import { AllComponentProps, textDefaultProps } from "../defaultProps";
import {message} from 'ant-design-vue'
import cloneDeep from "lodash-es/cloneDeep";
import { debounceChange, insertAt, cachedOldValue} from '@/helper'
import type { RespData, RespListData, RespWorkData} from './respTypes'

/**
 * 历史操作记录
 * @param id 单独标识符
 * @param componentId 组件id
 * @param type 操作类型 add delete modify
 * @param data 操作的数据
 * @param index 操作的组件在数组中的位置
 */
export interface HistoryProps {
  id: string;
  componentId?: string;
  type: 'add' | 'delete' | 'modify';
  data: any;
  index?: number;
}

/**
 * 修改组件属性的参数
 * @param key 组件属性的 key
 * @param value 组件属性的 value
 * @param id 组件的id
 * @param isRoot 是否是根组件
 */
export interface UpdateComponentData{
  key: keyof AllComponentProps | Array<keyof AllComponentProps>;
  value: string |string[];
  id: string;
  isRoot?: boolean;
}

/**
 * 每个图层元素的属性
 * @param props 组件属性
 * @param id 组件id
 * @param name 组件名称 l-text l-image l-shape
 * @param isLock 是否锁定
 * @param isHidden 是否隐藏
 * @param layerName 图层名称
*/
export interface ComponentData {
  // 这个元素的属性
  // props: { [key: string]: any };
  props: Partial<AllComponentProps>;
  // id, uuid v4 生成
  id: string;
  // 业务组件库名称 l-text ,l-image
  name: 'l-text' | 'l-image' | 'l-shape';
  // 图层相关属性
  isHidden?: boolean;
  isLock?: boolean;
  layerName?: string;
}

/** 
 * 整个编辑器的数据
 * @param components 组件列表
 * @param currentElement 当前编辑的元素 uuid
 * @param page 页面属性
 * @param copiedComponent 当前复制的组件
 * @param histories 历史记录
 * @param historyIndex 当前历史记录的操作位置
 */
export interface EditorProps {
  //供中间编辑器渲染的数组 与后端交互数据
  components: ComponentData[];
  //当前编辑元素 uuid
  currentElement: string;
  //项目信息 与后端交互数据
  page: PageData;
  //当前复制的组件
  copiedComponent?: ComponentData ;
  // 当前操作的历史记录
  histories: HistoryProps[];
  // 当前历史记录的操作位置
  historyIndex: number;
  //数据是否修改
  isDirty: boolean;
  // 当前work的渠道
  channels?: ChannelProps[];
}

/**
 * 作品的渠道
 */
export interface ChannelProps{
  id: number;
  name: string;
  workId: number;
  status: number;
}

/** 
 * 背景元素的属性
 * @param backgroundColor 背景颜色
 * @param backgroundImage 背景图片
 * @param backgroundRepeat 背景图片重复方式
 * @param backgroundSize 背景图片大小
 * @param height 高度
 */ 
export interface PageProps {
  backgroundColor: string;
  backgroundImage?: string;
  backgroundRepeat: string;
  backgroundSize: string;
  height: string;
}

export type MoveDirection = 'up' | 'down' | 'left' | 'right';

export type AllFormProps =  PageProps & AllComponentProps

/** 
 * 背景数据
 * @param props 背景属性
 * @param title 页面标题
 */ 
export interface PageData {
  props: PageProps;
  title: string;
  id?: string;
  desc?: string;
  coverImg?: string;
  uuid?: string;
  isHot?: boolean;
  isNew?: boolean;
  isTemplate?: boolean;
  settings?: { [key: string]: any };
  copiedCount?: number;
  status?: string;
  author?: string;
  user?: {
    gender: string;
    nickName: string;
    picture: string;
    userName: string;
  };
}


// npm install uuid --save
// npm install @types/uuid --save-dev
// console.log(uuidv4());
export const testComponents: ComponentData[] = [
  {
    id: uuidv4(),
    name: "l-text",
    props: {
      ...textDefaultProps,
      text: "hello 1",
      fontSize: "30",
      lineHeight: "1",
      textAlign: "left",
      width: '100px',
      height: '100px',
      backgroundColor:'#efefef',
      left: '10px',
      top: '10px'

    },
    layerName: "图层1",
    isHidden: false,
  },
  // {
  //   id: uuidv4(),
  //   name: "l-text",
  //   props: {
  //     ...textDefaultProps,
  //     text: "hello 2",
  //     fontSize: "20",
  //     fontWeight: "bold",
  //     lineHeight: "2",
  //     textAlign: "center",
  //     fontFamily: "Simsun",
  //   },
  //   layerName: "图层2",
  //   isHidden: false,
  // },
  // {
  //   id: uuidv4(),
  //   name: "l-text",
  //   props: {
  //     ...textDefaultProps,
  //     text: "hello 3",
  //     color: "red",
  //     fontSize: "15",
  //     actionType: "url",
  //     url: "https://www.baidu.com",
  //   },
  //   layerName: "图层3",
  //   isHidden: false,
  // },
];

const pageDefaultProps = { backgroundColor: '#ffffff',
  //  backgroundImage: 'url("https://static.imooc-lego.com/upload-files/screenshot-889755.png")', 
  // backgroundImage:'url("/assets/bg.png")',
   backgroundRepeat: 'no-repeat', backgroundSize: 'cover', height: '560px' }

//最大操作历史
const maxHistoryNumber = 20
const pushHistory = (state: EditorProps, historyRecord: HistoryProps) => {
  // check if historyIndex is already moved
  if (state.historyIndex !== -1) {
    // if already moved, we need delete all the records greater than the index
    state.histories = state.histories.slice(0, state.historyIndex)
    // move the historyIndex to the last  -1
    state.historyIndex = -1
  }
  // if histories length is less than max number, just push it to the end
  if (state.histories.length < maxHistoryNumber) {
    state.histories.push(historyRecord)
  } else {
    // if histories length is larger then max number,
    // 1 shift the first,
    // 2 push to last
    state.histories.shift()
    state.histories.push(historyRecord)
  }
}

/**
 * 历史属性修改的 undo和redo
 * @param state 
 * @param history 
 * @param type 
 */
const modifyHistory = (state: EditorProps, history: HistoryProps, type: 'undo' | 'redo') => {
  const { componentId, data } = history
  const { key, oldValue, newValue } = data
  // modify the page setting
  if (!componentId) {
    state.page.props[key as keyof PageProps] = type === 'undo' ? oldValue : newValue
  } else {
    const {element:updatedComponent} = store.getters.getElement(componentId);
    if (Array.isArray(key)) {
      key.forEach((keyName: string, index) => {
        updatedComponent.props[keyName] = type === 'undo' ? oldValue[index] : newValue[index]
      })
    } else {
      updatedComponent.props[key] = type === 'undo' ? oldValue : newValue
    }
  }
}

const setDirtyWrapper = (callback: Mutation<EditorProps>) => {
  return (state: EditorProps, payload: any)=>{
    state.isDirty = true;
    callback(state, payload);
  }
}

/**
 * store 存储着当前编辑器的数据
 */
const editor: Module<EditorProps, GlobalDataProps> = {
  state: {
    components: [],
    currentElement: "",
    page: {
      props: pageDefaultProps,
      title: 'test title'
    },
    histories: [],
    historyIndex: -1,
    isDirty: false,
    channels: [],
  },
  mutations: {
    /**
     * 向组件列表中添加新组件
     *
     * 此函数用于生成一个新的组件实例，并将其添加到给定的状态对象中的组件列表里
     * 它使用了uuidv4()函数来为新组件生成一个唯一的ID，确保在列表中的唯一性
     *
     * @param state 当前的组件列表状态对象，包含所有的组件信息
     * @param props 新组件的属性，这些属性将被赋予新创建的组件
     */
    // addComponent(state, props: Partial<TextComponentProps>) {
    //   // 创建一个新的组件实例，包括唯一的ID、默认名称'l-text'和传入的属性
    //   const newComponent: ComponentData = {
    //     id: uuidv4(),
    //     name: "l-text",
    //     props,
    //   };
    //   // 将新创建的组件添加到组件列表中
    //   state.components.push(newComponent);
    // },
    addComponent: setDirtyWrapper((state, newComponent: ComponentData) => {
      newComponent.isHidden=false;
      newComponent.isLock=false;
      newComponent.layerName = "图层" + (state.components.length+1);
      state.components.push(newComponent);

      pushHistory(state, {
        id: uuidv4(),
        componentId: newComponent.id,
        type: 'add',
        data: cloneDeep(newComponent)
      })
    }),
    deleteComponent: setDirtyWrapper((state, id: string) => {
      // 使用filter方法创建一个新的数组，只包含那些id与传入的id不相等的组件
      const {element:currentComponent, index} = store.getters.getElement(id);//state.components.find((item) => item.id === id);
      if(currentComponent){
        state.components = state.components.filter((item) => item.id !== id);
        // message.success(`已删除当前图层${currentComponent.layerName}`,1)
        pushHistory(state, {
          id: uuidv4(),
          componentId: currentComponent.id,
          type: 'delete',
          data: currentComponent,
          index: index
        })
      }
      
    }),
    setActive(state, currentId) {
      state.currentElement = currentId;
    },
    /**
     * 修改组件信息
     * @param id  修改的组件id,不存在直接使用currentElement
     * @param isRoot 是否是修改props还是根属性 
     */
    updateComponent: setDirtyWrapper((state, { key, value ,id, isRoot}: UpdateComponentData) => {
      // console.log(key,value,id);
      const {element:updateComponent} =  store.getters.getElement(id);
      // console.log(key, value ,id, isRoot);
      if (updateComponent) {
        if (isRoot) {
          // updateComponent[key as keyof ComponentData] = value; //ts 官方issue 31663
          updateComponent[key as string] = value;

        }else {
          const oldValue = Array.isArray(key) ? key.map((key: string) => updateComponent.props[key]) : updateComponent.props[key]
          console.log("oldValue",oldValue);
          debounceChange(oldValue, () => {
            pushHistory(state, {
              id: uuidv4(),
              componentId: (id || state.currentElement),
              type: 'modify',
              data: { oldValue: cachedOldValue, newValue: value, key , layerName: updateComponent.layerName }
            })
          })

          if (Array.isArray(key) && Array.isArray(value)) {
            key.forEach((keyName, index) => {
              updateComponent.props[keyName] = value[index]
            })
          } else if (typeof key === 'string' && typeof value === 'string'){
            updateComponent.props[key] = value
            // console.log(updateComponent.props);
          }
          // updateComponent.props[key as keyof AllComponentProps] = value;
        }

      }
    }),
    updatePage: setDirtyWrapper((state, { key, value, isRoot }) => {
      if(isRoot){
          (state.page as any)[key as keyof PageData] = value ;
      } else {
        if(state.page.props){
          state.page.props[key as keyof PageProps] = value;
        }
      }
      
    }),

    copyComponent(state, id) {
      const {element:currentComponent}=  store.getters.getElement(id);
      if(currentComponent){
        state.copiedComponent = currentComponent
        // message.success(`已拷贝当前图层${currentComponent.layerName}`,1)
      }
    },
    pasteComponent(state){
      if(state.copiedComponent){
        const newComponent = JSON.parse(JSON.stringify(state.copiedComponent)) as ComponentData;
        newComponent.id = uuidv4();
        newComponent.layerName = newComponent.layerName + '_副本';
        newComponent.props.left = parseInt(newComponent.props.left || '0') + 10 + 'px';
        newComponent.props.top = parseInt(newComponent.props.top || '0') + 10 + 'px';
        state.components.push(newComponent);
        state.currentElement = newComponent.id;

        pushHistory(state, {
          id: uuidv4(),
          componentId: newComponent.id,
          type: 'add',
          data: cloneDeep(newComponent)
        })
      }
    },
    moveComponent(state, data: { direction: MoveDirection; amount: number; id: number }) {
      const {element:currentComponent} = store.getters.getElement(data.id);
      if (currentComponent) {
        const oldTop = parseInt(currentComponent.props.top || '0')
        const oldLeft = parseInt(currentComponent.props.left || '0')
        const { direction, amount,id } = data;
        switch (direction) {
          case 'up':
            store.commit('updateComponent', {key: 'top', value: oldTop - amount + 'px', id});
            break;
          case 'down':
            store.commit('updateComponent', {key: 'top', value:  oldTop + amount + 'px', id});
            break;
          case 'left':
            store.commit('updateComponent', {key: 'left', value:   oldLeft - amount + 'px', id});
            break;
          case 'right':
            store.commit('updateComponent', {key: 'left', value:   oldLeft + amount + 'px', id});
            break;  
        }
      }

    },
     // undo history
    undo (state) {
      // never undo before
      if (state.historyIndex === -1) {
        // undo to the last item of the histories array
        state.historyIndex = state.histories.length - 1
      } else {
        // undo to the previous step
        state.historyIndex--
      }
      // get the record
      const history = state.histories[state.historyIndex]
      // process the history data
      switch (history.type) {
        case 'add':
          // if we create a component, then we should remove it
          state.components = state.components.filter(component => component.id !== history.componentId)
          break
        case 'delete':
          // if we delete a component, we should restore it at the right position
          state.components = insertAt(state.components, history.index as number, history.data)
          break
        case 'modify': {
          modifyHistory(state, history, 'undo')
          break
        }
        default:
          break
      }
    },
    redo (state) {
      // can't redo when historyIndex is the last item or historyIndex is never moved
      if (state.historyIndex === -1) {
        return
      }
      // get the record
      const history = state.histories[state.historyIndex]
      // process the history data
      switch (history.type) {
        case 'add':
          state.components.push(history.data)
          // state.components = insertAt(state.components, history.index as number, history.data)
          break
        case 'delete':
          state.components = state.components.filter(component => component.id !== history.componentId)
          break
        case 'modify': {
          modifyHistory(state, history, 'redo')
          break
        }
        default:
          break
      }
      state.historyIndex++
    },
    fetchWork(state, { data}: RespWorkData){
      console.log(data);
      const { content, ...rest}  = data
      console.log('state.page',state.page);
      state.page = {...state.page, ...rest};
      console.log('state.page',state.page);

      if(content.props){
        state.page.props = content.props;
      }
      state.components = content.components;
      console.log('state.components',state.components);

    },
    saveWork(state){
      state.isDirty = false;
    },
    fetchChannels(state, { data }: RespListData<ChannelProps>){
      console.log('fetchChannels',data);
      state.channels = data.list;
    },
    createChannel(state, { data }: RespData<ChannelProps>){
      // state.channels?.push(data);
      state.channels = [ ...state.channels || [], data].flat()
    },
    deleteChannel(state, { payload }: RespData<any>){
      if(payload && payload.urlParams){
        const { urlParams } = payload;
        state.channels = state.channels?.filter((channel) => channel.id !== parseInt(urlParams.id));
      }
    },

  },
  getters: {
    getCurrentElement: (state) => {
      return state.components.find((item) => item.id === state.currentElement);
    },
    getElement: (state) => (id: string) => {
      // return state.components.find((item) => item.id === (id||state.currentElement));
      const index = state.components.findIndex((item) => item.id === (id || state.currentElement));
      const element = index !== -1 ? state.components[index] : undefined;
      return { element, index };
    },
    checkUndoDisable: (state) => {
      // no history item or move to the first item
      if (state.histories.length === 0 || state.historyIndex === 0) {
        return true
      }
      return false
    },
    checkRedoDisable: (state) => {
      // 1 no history item
      // 2 move to the last item
      // 3 never undo before
      if (state.histories.length === 0 ||
        state.historyIndex === state.histories.length ||
        state.historyIndex === -1) {
        return true
      }
      return false
    }
  },
  actions: {
    fetchWork: actionWrapper('/works/:id','fetchWork'),
    saveWork: actionWrapper('/works/:id','saveWork', { method: 'patch'}),
    publishWork: actionWrapper('/works/publish/:id','publishWork', { method: 'post'}),
    // fetchChannels: actionWrapper('/channel/getWorkChannels/:id','fetchChannels'),
    fetchChannels: actionWrapper('/channel','fetchChannels'),
    createChannel: actionWrapper('/channel','createChannel', { method: 'post'}),
    deleteChannel: actionWrapper('/channel/:id','deleteChannel', { method: 'delete'}),
  }
};

export default editor;
